package controllers

// 导入相关的包
import (
    "os"
    "net"
    "fmt"
    "log"
    "time"
    //"errors"
    "net/url"
    "strings"
    "strconv"
    "net/http"
    "io/ioutil"
    "encoding/json"
    "bee-api/models"
   	"github.com/astaxie/beego"
)

// 定义控制器
type MapController struct {
    beego.Controller
}

// 返回数据结构体
type ResultData struct {
    Code  int         `json:"code"`
    Msg   string      `json:"msg"`
    Data  interface{} `json:"data"`
}

// URLMapping ...
func (c *MapController) URLMapping() {
    c.Mapping("GetCityByIP", c.GetCityByIP)
    c.Mapping("GetCoordinate", c.GetCoordinate)
    c.Mapping("GetAddressByLngLat", c.GetAddressByLngLat)
    c.Mapping("GetLatLngByAddres", c.GetLatLngByAddres)
}

//----------------------------------
// 地图相关接口 － 百度、阿里
// 在线接口文档：见相应官方网站
//----------------------------------

// GetCityByIP ...
// @Title 根据ip获取城市信息
// @Description 根据ip获取城市信息 type 1百度 2高德
// @router /GetCityByIP [get]
func (c *MapController) GetCityByIP() {

    // 接受请求参数
   	ip := c.Ctx.Input.Query("ip")
   	mtype := c.Ctx.Input.Query("type")

   	if ip == ""{
   		errMsg := map[string] string{
   			"code" : "10001",
			"msg" : "IP地址不能为空",
   		}
   		c.Data["json"] = errMsg
		c.ServeJSON()
   	}

   	// 服务商默认使用高德 1百度 2高德
   	if mtype < "1" || mtype > "2"{
   		mtype = "2"
   	}

   	// 初始化参数
	param := url.Values{}

   	// api地址
    mapURL := ""
    // explain申明
    explain := ""
   	if mtype == "2" {
   		// 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
		param.Set("ip",ip)          	// ip地址
		param.Set("key",beego.AppConfig.String("gaodemapappkey"))	// APPkey
		param.Set("output","JSON")		// 返回数据格式
		mapURL = "http://restapi.amap.com/v3/ip"
        explain = "调用高德根据ip获取城市信息"
   	}else{
   		// 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
		param.Set("ip",ip)          	// ip地址
		param.Set("ak",beego.AppConfig.String("baidumapappkey"))	// APPkey
		param.Set("output","JSON")		// 返回数据格式
   		mapURL = "http://api.map.baidu.com/location/ip"
        explain = "调用百度根据ip获取城市信息"
   	}

   	// 发送请求
   	data,err := GetTest(mapURL,param)

    // 获取ip信息
    ips, _ := GetIpInfo()
    // 获取当前时间
    nowDate := time.Now().Format("2006-01-02 15:04:05")
    // 记录调用信息
    AddApiLog := &models.AddApiLogStruct{
        Explain:    explain,
        CreateDate: nowDate,
        Ip:         ips,
        ApiUrl:     mapURL,
    }

    appLog := make(map[string]string)

    appLog, _, _ = AddApiLog.ApiLogSave()

    fmt.Println("applog info :",appLog)

   	if err != nil {
	  	c.Data["json"] = err.Error()
        c.ServeJSON()
	} else {
		// 定义无类型数据集合
		var netReturn map[string]interface{}
		json.Unmarshal(data,&netReturn)
        data := make(map[string] interface{})
        addInfo := make(map[string] interface{})

		// 高德
        if mtype == "2" {
            //fmt.Println(netReturn)
            if netReturn["status"] == "1" {
                // 数据处理
                addInfo["city"] = netReturn["city"]
                addInfo["province"] = netReturn["province"]
                addInfo["point"] = netReturn["rectangle"]
                data["code"] = "0000"
                data["msg"] = "请求成功"
                data["data"] = addInfo
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 百度
        if mtype == "1" {
            //fmt.Println(netReturn)
            if netReturn["status"].(float64) == 0 {
                // 数据处理
                content := netReturn["content"].(map[string]interface{})
                address_detail := content["address_detail"].(map[string]interface{})
                point := content["point"].(map[string]interface{})

                addInfo["city"] = address_detail["city"]
                addInfo["province"] = address_detail["province"]
                // y := strconv.FormatFloat(point["y"].(float64),'f',-1,64)
                // x := strconv.FormatFloat(point["x"].(float64),'f',-1,64)
                addInfo["point"] = strings.Join([]string{point["y"].(string), point["x"].(string)}, ",")
                data["code"] = "0000"
                data["msg"] = "请求成功"
                data["data"] = addInfo

                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 其他情况
        errMsg := map[string] string{
            "code": "10014",
            "msg": "系统内部异常",
        }
        c.Data["json"] = errMsg
        c.ServeJSON()
	}
}

// GetCoordinate ...
// @Title 经纬度坐标系转换接口
// @Description 经纬度坐标系转换接口
// @router /GetCoordinate [get]
func (c *MapController) GetCoordinate() {

    lat  := c.Ctx.Input.Query("lat")     //源坐标
    lng  := c.Ctx.Input.Query("lng")     //源坐标
    from := c.Ctx.Input.Query("from")    //源坐标类型 可选值：gps;mapbar;baidu;gaode;
    mtype:= c.Ctx.Input.Query("type")    //服务类型

    if lat == "" || lng == "" || from == "" {
        errMsg := map[string] string{
            "code" : "10001",
            "msg" : "经纬度信息不能为空",
        }
        c.Data["json"] = errMsg
        c.ServeJSON()
    }

    // 服务商默认使用高德 1百度 2高德
    if mtype < "1" || mtype > "2"{
        mtype = "2"
    }

    // 初始化参数
    param := url.Values{}
    // api地址
    mapURL := ""
    // 接口说明
    explain := ""
    // 将经纬度处理成字符串
    location := strings.Join([]string{lng, lat}, ",")
    // 获取坐标体系
    from = getFromKey(from,mtype)

    if mtype == "1" {
        //fmt.Println(location)
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("coords",location)    // 经纬度
        param.Set("ak",beego.AppConfig.String("baidumapappkey"))     // APPkey
        param.Set("output","json")      // 返回数据格式
        param.Set("from",from)          // 源坐标系
        mapURL = "http://api.map.baidu.com/geoconv/v1/"
        explain = "调用百度接口进行坐标系转换"
    }else{
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("locations",location) // 请求的经纬度
        param.Set("key",beego.AppConfig.String("gaodemapappkey"))    // APPkey
        param.Set("output","JSON")      // 返回数据格式
        param.Set("coordsys",from)      // 源坐标系
        mapURL = "http://restapi.amap.com/v3/assistant/coordinate/convert"
        explain = "调用高德接口进行坐标系转换"
    }

    // 发送请求
    data,err := GetTest(mapURL,param)

    // 获取ip信息
    ips, _ := GetIpInfo()
    // 获取当前时间
    nowDate := time.Now().Format("2006-01-02 15:04:05")
    // 记录调用信息
    AddApiLog := &models.AddApiLogStruct{
        Explain:    explain,
        CreateDate: nowDate,
        Ip:         ips,
        ApiUrl:     mapURL,
    }

    appLog := make(map[string]string)

    appLog, _, _ = AddApiLog.ApiLogSave()

    fmt.Println("applog info :",appLog)

    if err != nil{
        c.Data["json"] = err.Error()
        c.ServeJSON()
    }else{
        // 定义数据集合
        var netReturn map[string]interface{}
        json.Unmarshal(data,&netReturn)
        data := make(map[string] interface{})
        info := make(map[string] interface{})

        // 高德
        if mtype == "2" {
            if netReturn["status"] == "1" {
                //fmt.Println(netReturn)
                data["code"] = "0000"
                data["msg"] = "请求成功"
                info["locations"] = netReturn["locations"]
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 百度
        if mtype == "1" {
            if netReturn["status"].(float64) == 0 {
                //fmt.Println(netReturn)
                result := netReturn["result"].([]interface{})
                location := result[0].(map[string]interface{})
                //fmt.Println(location)
                data["code"] = "0000"
                data["msg"] = "请求成功"
                lng := strconv.FormatFloat(location["x"].(float64),'f',-1,64)
                lat := strconv.FormatFloat(location["y"].(float64),'f',-1,64)
                info["locations"] = strings.Join([]string{lng,lat},",")
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 其他情况
        errMsg := map[string] string{
            "code": "10014",
            "msg": "系统内部异常",
        }
        c.Data["json"] = errMsg
        c.ServeJSON()
    }
}

// GetAddressByLngLat ...
// @Title 经纬度转地址
// @Description 地址转经纬度 lat lng 经纬度信息 ;type 服务商类型 type 1百度 2高德
// @router /GetAddressByLngLat [get]
func (c *MapController) GetAddressByLngLat() {
	// 接受请求参数
    lat := c.Ctx.Input.Query("lat")
    lng := c.Ctx.Input.Query("lng")
    mtype := c.Ctx.Input.Query("type")

    // 参数判断
    if lat == "" || lng == ""{
        errMsg := map[string] string{
            "code" : "10001",
            "msg" : "经纬度信息不能为空",
        }

        c.Data["json"] = errMsg
        c.ServeJSON()
    }

    // 服务商默认使用高德 1百度 2高德
    if mtype < "1" || mtype > "2"{
        mtype = "2"
    }

    // 初始化参数
    param := url.Values{}
    // api地址
    mapURL := ""
    // 接口log说明
    explain := ""
    // 将经纬度拼接成字符串
    location := strings.Join([]string{lng, lat}, ",")

    if mtype == "1" {
        fmt.Println(location)
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("ak",beego.AppConfig.String("baidumapappkey"))     // APPkey
        param.Set("output","json")      // 返回数据格式
        param.Set("location",location)  // 请求的经纬度
        param.Set("coord_type","bd09ll")// bd09ll（百度经纬度坐标）、gcj02ll（国测局经纬度坐标）、wgs84ll（wgs84经纬度坐标）
        param.Set("geotable_id","81234")// 与ak配合鉴权
        mapURL = "http://api.map.baidu.com/cloudrgc/v1"
        explain = "调用百度经纬度转地址接口"
    }else{
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("location",location)  // 请求的经纬度
        param.Set("key",beego.AppConfig.String("gaodemapappkey"))    // APPkey
        param.Set("output","JSON")      // 返回数据格式
        mapURL = "http://restapi.amap.com/v3/geocode/regeo"
        explain = "调用高德经纬度转地址接口"
    }

    // 发送请求
    data,err := GetTest(mapURL,param)

    // 获取ip信息
    ips, _ := GetIpInfo()
    // 获取当前时间
    nowDate := time.Now().Format("2006-01-02 15:04:05")
    // 记录调用信息
    AddApiLog := &models.AddApiLogStruct{
        Explain:    explain,
        CreateDate: nowDate,
        Ip:         ips,
        ApiUrl:     mapURL,
    }

    appLog := make(map[string]string)

    appLog, _, _ = AddApiLog.ApiLogSave()

    fmt.Println("applog info :",appLog)

    if err != nil{
        c.Data["json"] = err.Error()
        c.ServeJSON()
    }else{
        // 定义数据集合
        var netReturn map[string]interface{}
        json.Unmarshal(data,&netReturn)
        data := make(map[string] interface{})
        info := make(map[string] interface{})

        // 高德
        if mtype == "2" {
            if netReturn["status"] == "1" {
                regeocode := netReturn["regeocode"].(map[string]interface{})
                data["code"] = "0000"
                data["msg"] = "请求成功"
                info["addres"] = regeocode["formatted_address"]
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 百度
        if mtype == "1" {
            fmt.Println(netReturn)
            if netReturn["status"].(float64) == 0 {
                fmt.Println(netReturn,location)
                data["code"] = "0000"
                data["msg"] = "请求成功"
                info["addres"] = netReturn["formatted_address"]
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 其他情况
        errMsg := map[string] string{
            "code": "10014",
            "msg": "系统内部异常",
        }
        c.Data["json"] = errMsg
        c.ServeJSON()
    }
}

// GetLatLngByAddres ...
// @Title 地址转经纬度
// @Description 经纬度转地址
// @router /GetLatLngByAddres [get]
func (c *MapController) GetLatLngByAddres() {
	// 接受请求参数
    address := c.Ctx.Input.Query("addres")
    mtype := c.Ctx.Input.Query("type")

    // 参数判断
    if address == "" {
        errMsg := map[string] string{
            "code" : "10001",
            "msg" : "地址信息不能为空",
        }

        c.Data["json"] = errMsg
        c.ServeJSON()
    }

    // 服务商默认使用高德 1百度 2高德
    if mtype < "1" || mtype > "2"{
        mtype = "2"
    }

    // 初始化参数
    param := url.Values{}
    // api地址
    mapURL := ""
    // 接口log说明
    explain := ""

    if mtype == "1" {
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("address",address)    // 地址
        param.Set("city","")            // 城市
        param.Set("ak",beego.AppConfig.String("baidumapappkey"))     // APPkey
        param.Set("output","json")      // 返回数据格式
        mapURL = "http://api.map.baidu.com/cloudgc/v1"
        explain = "调用百度接口地址转经纬度"
    }else{
        // 配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
        param.Set("address",address)    // 地址
        param.Set("city","")            // 城市
        param.Set("key",beego.AppConfig.String("gaodemapappkey"))    // APPkey
        param.Set("output","JSON")      // 返回数据格式
        mapURL = "http://restapi.amap.com/v3/geocode/geo"
        explain = "调用高德接口地址转经纬度"
    }

    // 发送请求
    data,err := GetTest(mapURL,param)

    // 获取ip信息
    ips, _ := GetIpInfo()
    // 获取当前时间
    nowDate := time.Now().Format("2006-01-02 15:04:05")
    // 记录调用信息
    AddApiLog := &models.AddApiLogStruct{
        Explain:    explain,
        CreateDate: nowDate,
        Ip:         ips,
        ApiUrl:     mapURL,
    }

    appLog := make(map[string]string)

    appLog, _, _ = AddApiLog.ApiLogSave()

    fmt.Println("applog info :",appLog)

    if err != nil{
        c.Data["json"] = err.Error()
        c.ServeJSON()
    }else{
        // 定义数据集合
        var netReturn map[string]interface{}
        json.Unmarshal(data,&netReturn)
        data := make(map[string] interface{})
        info := make(map[string] interface{})

        fmt.Println(netReturn,mtype)

        // 高德
        if mtype == "2" {
            // fmt.Println(netReturn)
            if netReturn["status"] == "1" {
                geocodes := netReturn["geocodes"].([]interface{})
                geocodesInfo := geocodes[0].(map[string]interface{})
                fmt.Println(geocodesInfo["location"])
                data["code"] = "0000"
                data["msg"] = "请求成功"
                info["city"] = geocodesInfo["city"]
                info["level"] = geocodesInfo["level"]
                info["district"] = geocodesInfo["district"]
                info["province"] = geocodesInfo["province"]
                info["location"] = geocodesInfo["location"]
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 百度
        if mtype == "1" {

            if netReturn["status"].(float64) == 0 {
                result := netReturn["result"].([]interface{})
                location := result[0].(map[string]interface{})
                latlng := location["location"].(map[string]interface{})
                address_components := location["address_components"].(map[string]interface{})

                fmt.Println(latlng)
                lat := strconv.FormatFloat(latlng["lat"].(float64), 'f', -1, 64)
                lng := strconv.FormatFloat(latlng["lng"].(float64), 'f', -1, 64)
                fmt.Println(lat,lng)
                data["code"] = "0000"
                data["msg"] = "请求成功"
                info["location"] = strings.Join([]string{lng, lat}, ",")
                info["city"] = address_components["city"]
                info["level"] = address_components["level"]
                info["district"] = address_components["district"]
                info["province"] = address_components["province"]
                data["data"] = info
                c.Data["json"] = data
                c.ServeJSON()
            }
        }
        // 其他情况
        errMsg := map[string] string{
            "code": "10014",
            "msg": "系统内部异常",
        }
        c.Data["json"] = errMsg
        c.ServeJSON()
    }
}

// get 网络请求
func GetTest(apiURL string,params url.Values)(rs[]byte ,err error){

    var Url *url.URL
    Url,err = url.Parse(apiURL)

    if err != nil{
        fmt.Printf("解析url错误:\r\n%v",err)
        return nil,err
    }

    // 如果参数中有中文参数,这个方法会进行URLEncode
    Url.RawQuery = params.Encode()
    resp,err := http.Get(Url.String())

    if err != nil{
        fmt.Println("err:",err)
        return nil,err
    }

    defer resp.Body.Close()
    return ioutil.ReadAll(resp.Body)
}
  
// post 网络请求 ,params 是url.Values类型
func PostTest(apiURL string, params url.Values)(rs[]byte,err error){

    resp,err := http.PostForm(apiURL, params)

    if err != nil{
      return nil ,err
    }
    defer resp.Body.Close()
    return ioutil.ReadAll(resp.Body)
}

func getFromKey(from string,mtype string)(string){
    switch from {
        case "gps" :
            if mtype == "1" {
                from = "1"
            }else{
                from = "gps"
            }
            break;
        case "mapbar" :
            if mtype == "1" {
                from = "7"
            }else{
                from = "mapbar"
            }
            break;
        case "baidu" :
            if mtype == "1" {
                from = "5"
            }else{
                from = "baidu"
            }
            break;
        case "gaode" :
            if mtype == "1" {
                from = "3"
            }else{
                from = "autonavi"
            }
            break;
        default :
            from = "";
            break;
    }
    return from;
}

/**
 * 获取ip信息
 */
func GetIpInfo() (ips string, err error) {

    addrs, err := net.InterfaceAddrs()
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    for _, address := range addrs {
        // 检查ip地址判断是否回环地址
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                log.Println(ipnet.IP.String())
                ips = ipnet.IP.String()
            }
        }
    }
    return
}

